package com.supermap.application.service;

import com.supermap.application.common.*;
import com.supermap.application.dao.*;
import com.supermap.application.entity.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName MacroTablemetaService
 * @Description TODO
 * @Author HEKE
 * @Date 2019/2/24 22:03
 */

@Service
public class MacroTablemetaService extends BaseService{

    /** 实体管理 */
    @Autowired
    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private MacroTablemetaDao macroTablemetaDao;

    @Autowired
    private MacroIdenmetaDao macroIdenmetaDao;

    @Autowired
    private RegionInfoDao regionInfoDao;

    @Autowired
    private MacroTableinfoDao macroTableinfoDao;


    public List<TMacroTablemeta> getByMatmids(int[] matmids) {
        return macroTablemetaDao.findAllByMatmids(matmids);
    }

    /**
     * 获取行政区划级别、报告期类型的parid下的目录/表/指标
     *
     * @param regionLevel
     * @param reportType
     * @param parid
     * @return
     */
    public List<TMacroTablemeta> listRoot(int parid, int regionLevel, int reportType) {
        if(regionLevel == -1){
            return  macroTablemetaDao.findAllByParidAndreportType(parid,reportType);
        }
        return macroTablemetaDao.findAllByRegionlevelAndreportType(parid, regionLevel, reportType);
    }

    public List<TMacroTablemeta> getByParidAndreportType(int parid, int reportType) {
        return macroTablemetaDao.findAllByParidAndreportType(parid, reportType);
    }

    /**
     * 获取指标为枚举分组指标对象
     * @param tablemeta
     * @return
     */
    public List<TMacroIdenmeta> findAllGroupInd(TMacroTablemeta tablemeta){
        List<TMacroIdenmeta> re = this.macroIdenmetaDao.findGroupInd(tablemeta.getMatmid());
        return re ;
    }

    public String recogniseTableName(int regionLevel) {
        String tableName = "T_MACRO_WDDATA";
        switch (regionLevel) {
            case 1:
                tableName = "T_MACRO_WDDATA";
                break;
            case 2:
                tableName = "T_MACRO_SNDATA";
                break;
            case 3:
                tableName = "T_MACRO_SHDATA";
                break;
            case 4:
                tableName = "T_MACRO_XNDATA";
                break;
            case 5:
                tableName = "T_MACRO_XADATA";
                break;
            case 6:
                tableName = "T_MACRO_CNDATA";
                break;
            case 7:
                tableName = "T_MACRO_XQDATA";
                break;
            case 8:
                tableName = "T_MACRO_OTHERDATA";
                break;
            case 9:
                tableName = "T_TSMACRO_DATA";
                break;
            default:
                break;
        }
        return tableName;
    }

    public TMacroTablemeta getOne(int mtmid) {
        return macroTablemetaDao.getOne(mtmid);
    }


    /**
     * 综合查询 三个维度的指标数据：  全行政区划+全指标+全时段
     *
     * @param tableName
     * @param query
     * @return
     */
    public List<Object> queryAllData(String tableName, MacroQuery query, String indicatorCodes) {
        String sql = this.getSql(tableName,query,indicatorCodes);
        BaseDaoImpl<TMacroTablemeta,Integer> new_dao = new BaseDaoImpl<>(TMacroTablemeta.class,entityManager);
        try {
            System.out.println("综合查询："+sql);
            return new_dao.query(sql);
        }catch (Exception e){
            System.out.println("综合查询异常："+sql);
            e.printStackTrace();
            return new ArrayList<>();
        }
    }

    /**
     * 根据指标精度将数据格式化，比如保留两位小数点
     * @param data
     * @param indicators
     * @param isOneIden
     * @return
     */
    public List<Object> formatPrecision(List<Object> data,List<TMacroTablemeta> indicators,boolean isOneIden){
        List<Object> newData = new ArrayList<>();
        Map<String,Integer> map = new HashMap<>() ;
        //找到歌指标的精度 分组指标也在内
        for(TMacroTablemeta ind:indicators){
            List<TMacroIdenmeta> idenmetas = macroIdenmetaDao.findByTablemeta(ind.getMatmid());
            for(TMacroIdenmeta idenmeta:idenmetas){
                map.put(idenmeta.getIdenCode(),idenmeta.getIdenPrecision());//指标设置精度值
            }
        }
        for(Object o:data){
            Object[] objs = (Object[]) o;
            Object[] newR = new Object[objs.length] ;
            for(int i=0,len=objs.length; i<len; i++){
                //第四列为数值是数值
                if(i == len-1){
                    String idenCode = isOneIden?indicators.get(0).getIdenCode():objs[4].toString();
                    Integer precision = map.get(idenCode);//指标设置精度值
                    if(null == precision){
                        precision = 2 ;//默认精度为2
                    }
                    DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
                    df.setMaximumFractionDigits(precision);
                    df.setMinimumFractionDigits(precision);
                    df.setGroupingUsed(false);
                    newR[i] = df.format(null==objs[i] ? 0 : Float.parseFloat(objs[i].toString())) ;
                    continue;
                }
                newR[i] = objs[i] ;
            }
            newData.add(newR);
        }
        return  newData ;
    }


    /**
     * 前端传过来的 行政区划带##需要预处理下
     *
     * @param regions
     * @return
     */
    public Region[] preHandleRegion(int catalogid, Region[] regions, MacroQuery macroQuery) {
        List<Region> regionList = new ArrayList<>();
        int len = regions.length;
        for(int i=0; i<len; i++){
            Region r = regions[i];
            String code = r.getRegionCode();
            if(code.contains("#")) {
                if(code.equals("000000000000")){
                    code ="";
                }else{
                    code =code.substring(0,code.indexOf("#"));
                }
                int regionlevel=macroQuery.getRegionLevel();

                if (RegionSupport.isMunicipalRegion(code) && code.indexOf("00") != -1) {
                    code = code.substring(0, code.indexOf("00"));//取直辖市的前两位
                }
                List<TRegioninfo> regioninfoList = this.regionInfoDao.getLeafRegion(catalogid, regionlevel, code + "%");
                List fooList = new ArrayList<Region>();
                for (TRegioninfo t : regioninfoList) {
                    Region rr  = new Region(t.getRegioncode(), t.getName(), t.getRegionlevel());
                    fooList.add(rr);
                }
                regionList.addAll(fooList);
            }else{
                regionList.add(r);
            }
        }
        int size = regionList.size();
        Region[] reRegions = new Region[size];
        for(int i =0;i<size;i++){
            reRegions[i] = regionList.get(i);
        }

        return reRegions;
    }

    /**
     * 综合查询SQL组构
     * @param tableName 数据表名（分行政级别）
     * @param query 查询条件
     * @param indicatorCodes 查询指标编码组（逗号分隔，包括分组子指标）
     * */
    public String getSql(String tableName, MacroQuery query, String indicatorCodes){
        Region[] regions = query.getRegions();
        String regionSql = RegionSupport.regionsToSql(regions, query.getRegionLevel());//区域条件，指定（带#）区域级别
        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append("select p.year,p.month,p.regioncode,s.name,p.iden_code,p.iden_value from " + tableName + " p");
        sqlBuilder.append(" inner join t_regioninfo s on p.regioncode = s.regioncode");
        sqlBuilder.append(" where s.rcid = " + query.getCatalog());
        if(regionSql.length()>0) {
            sqlBuilder.append(" and " + regionSql);
        }
        String idenSql = " and p.iden_code in(" + indicatorCodes + ")";//指标条件
        if(indicatorCodes.indexOf(",")==-1){
            idenSql = " and p.iden_code = " + indicatorCodes;
        }
        String timeRankSql = PeriodSupport.getTimeRankSql(query.getTimeRank(), query.getReportType());//报告期条件
        sqlBuilder.append(" and " + timeRankSql + idenSql);
        sqlBuilder.append(" and p.regioncode is not null order by s.regioncode, p.year, p.month asc");
        return sqlBuilder.toString();
    }


    /**
     * 封装综合数据结果对象
     * @param data 查询数据（报告期+区划+指标+值）
     * @param periods 报告期
     * @param indicators 综合查询指定指标
     * @param regions 查询区划
     * @return
     */
    public MacroDataResult formatAllData(List<Object> data, List<TMacroPeriod> periods, List<TMacroTablemeta> indicators, Region[] regions, String[] groupIdenCodes) {
        MacroDataResult re = new MacroDataResult();//综合三视图数据结果对象
        re.setStatus(true);
        int colNum = periods.size() * indicators.size();//列：报告期长度*指标长度
        List peridList = new ArrayList();//报告期时段
        List<MacroReIndicator> indicatorList = new ArrayList();//指标集

        List head = new ArrayList();//表格标题
        head.add("行政区划代码");
        head.add("行政区划名称");

        //获取查询的时段 指标 表头等信息
        Map<String,Object> map = new HashMap<>();
        map = getHeadInfos(periods,indicators,groupIdenCodes);
        peridList = (List)map.get("period");//报告期
        indicatorList = (List<MacroReIndicator>)map.get("indicator");//指标结果项
        head.addAll((List)map.get("head"));//列表头（报告期*指标项）

        ///////////////////////
        String[][] content = new String[regions.length][head.size()];
        //填充查询数据
        for (int i=0,size=data.size(); i<size; i++) {
            Object[] objs = (Object[]) data.get(i);
            int year = Integer.parseInt(objs[0].toString());
            int month = Integer.parseInt(objs[1].toString());

            String regioncode = objs[2].toString();
            String regionname = objs[3].toString();

            String idencode = objs[4].toString();
            int colIndex = getColIndex(year, month, idencode, peridList, indicatorList,groupIdenCodes);//（报告期*指标）所在列序号
            int rowIndex = getRowIndex(regioncode, regions);//（区域）所在行序号
            if (colIndex != -1 && rowIndex != -1) {
                String val = objs[5] != null ? objs[5].toString() : "0";//没有数据为0，是否合理？？？
                if (val.equals("") || val.equals("null") || val.equals(null)) {
                    val = "0";
                }
                content[rowIndex][0] = regioncode;
                content[rowIndex][1] = regionname;
                content[rowIndex][colIndex + 2] = val;
            }
        }
        ///////////////////////

        re.setIndicators(indicatorList);//指标集
        re.setPeriods(peridList);//报告期时段集
        re.setHead(head);//表格列标题
        re.setContent(MacroDataResult.removeNull(content));//表格行数据
        return re;
    }


    /**
     * 获取（时段*指标）表头信息
     * @param periods 报告期
     * @param indicators 前台选择指标
     * @return
     */
    private Map<String,Object> getHeadInfos(List<TMacroPeriod> periods,List<TMacroTablemeta> indicators,String[] groupIdenCodes){
        List peridList = new ArrayList();//报告期时段
        //报告期项
        for (TMacroPeriod t : periods) {
            Period p = new Period();
            p = (Period) convertBeanTOBean(t,p);
            peridList.add(p);
        }
        //指标项
        List<MacroReIndicator> indicatorList = new ArrayList();//指标结果集
        for (TMacroTablemeta t : indicators) {
            MacroReIndicator ind = getSubIndicators(t);//指标与枚举分组（子指标）
            if(ind==null){
                continue;
            }
            ind.setPeriods(peridList);//报告期
            ind.setIdenName(fullfillIndName(ind.getIdenName(),ind.getIdenUnit()));
            indicatorList.add(ind);//指标
        }
        if(indicatorList.size()<1) {
            System.out.println("综合查询指标配置全null，请配置！");
        }
        //分组指标转map
        Map<String,String> groupCodes = new HashMap<>();
        if(groupIdenCodes!=null){
            for(int i = 0; i < groupIdenCodes.length ; i++){
                groupCodes.put(groupIdenCodes[i],groupIdenCodes[i]);
            }
        }

        //表头
        List head = new ArrayList();
        for (int pi=0,size=peridList.size(); pi<size; pi++) {
            Period p =(Period) peridList.get(pi);
            for(MacroReIndicator r:indicatorList){
                head.addAll(getIndHead(p, r,groupCodes)) ;//添加列表头项（支持多层子项）
            }
        }
        Map<String,Object> map = new HashMap<>();
        map.put("period",peridList);//报告期
        map.put("indicator",indicatorList);//指标结果项
        map.put("head",head);//报告期*指标项
        return  map;
    }


    /**
     * 获取某个时段某个指标的表头部分
     * @param r
     * @return
     */
    private List getIndHead(Period p ,MacroReIndicator r,Map<String,String> groupIdenCodes){
        List<String> head = new ArrayList<>();
        String prefix = PeriodSupport.getPrefix(p);//获取报告期前缀
        List<Period> hasPeriods = r.getPeriods();//指标对应报告期
        int count = 0 ;
        for(Period period:hasPeriods){
            if(p.getReportType()==period.getReportType() && p.getYear()==period.getYear()
                    && p.getMonth()==period.getMonth()){
                count = 1;
                break;
            }
        }
        //如果该时段下有此指标
        if(count == 1){
            if(groupIdenCodes != null && !groupIdenCodes.isEmpty()){
                if(groupIdenCodes.get("'"+r.idenCode+"'")!=null){
                    head.add(prefix+" "+fullfillIndName(r.getIdenName(),r.getIdenUnit()));
                }
            }else {
                head.add(prefix+" "+fullfillIndName(r.getIdenName(),r.getIdenUnit()));
            }
            List<MacroReIndicator> subs = r.getSubs();//子指标项（包括本级）
            for(MacroReIndicator sub:subs){
                head.addAll(getIndHead(p,sub,groupIdenCodes));//解析嵌套子指标表头（支持多层表头）
            }
        }
        return  head ;
    }


    /**解析分组子指标 树形结构*/
    public MacroReIndicator getSubIndicators(TMacroTablemeta tablemeta){
        int matmid = tablemeta.getMatmid();//指标ID
        if(matmid==0) {
            System.out.println("综合指标ID为null");
            return null;
        }
        List<TMacroIdenmeta> idenmetas = macroIdenmetaDao.findByTablemeta(matmid);//是否分组
        if(idenmetas.size()==0){
            System.out.println("综合指标ID（"+matmid+"）未配置T_MACRO_IDENMETA指标项");
            return null;
        }
        MacroReIndicator mri = pushGroupIndicators(idenmetas.get(0));//指标枚举分组（多层子指标）
        return mri;
    }

    /**
     * 指标枚举分组的树结构节点值（指标、报告期）填充（支持多层）
     * @param idenmeta
     * @return
     */
    private MacroReIndicator pushGroupIndicators(TMacroIdenmeta idenmeta){
        MacroReIndicator ind = new MacroReIndicator();
        ind = (MacroReIndicator) convertBeanTOBean(idenmeta,ind);//对象属性赋值
        TMacroIdenvl idenvl = idenmeta.getTMacroIdenvl() ;
        String parid = "0";
        if(null != idenvl){
            parid = idenvl.getCode();
            List<TMacroPeriod> periodList= macroTableinfoDao.findPeriodsByIdenCode(idenmeta.getIdenCode());
            //分组指标包含的时段
            List<Period> periods = new ArrayList<>();
            for(TMacroPeriod p :periodList){
                Period t = new Period();
                t = (Period)convertBeanTOBean(p,t);
                ind.getPeriods().add(t);
            }
        }
        List<TMacroIdenmeta> subInds = macroIdenmetaDao.findGroupIndByParid(idenmeta.getTMacroTablemeta().getMatmid()
                ,parid);//获取下一层子指标
        for(TMacroIdenmeta gInd:subInds){
            ind.getSubs().add(pushGroupIndicators(gInd));//嵌套生成
        }
        return  ind;
    }

    /**
     * 读取列（报告期*指标项）序号值（三维转二维数组）
     *
     * @param year
     * @param month
     * @param idencode 原指标
     * @param periods  指标报告期
     * @param indicators 解析后指标列表头项（含分组指标）
     * @return
     */
    private int getColIndex(int year, int month, String idencode, List<Period> periods, List<MacroReIndicator> indicators,String[] groupIdencodes) {
        int index = -1 ;
        //分组指标转map
        Map<String,String> groupCodes = new HashMap<>();
        if(groupIdencodes!=null){
            for(int i = 0; i < groupIdencodes.length ; i++){
                groupCodes.put(groupIdencodes[i],groupIdencodes[i]);
            }
        }

        for (int i=0,size=periods.size(); i<size; i++) {
            Period p = periods.get(i);
            for (int j=0,size2=indicators.size(); j<size2; j++) {
                boolean isFind = false ;
                List<String> head = getIndCode(p, indicators.get(j),groupCodes);//报告期下的多维表头指标(含分组子指标)
                if(!(year==p.getYear() && month==p.getMonth())){
                    index += head.size();//指标项个数（含子指标）
                    continue;
                }
                for(String h:head){
                    index++;
                    if(h.equals(idencode)){//指标相同
                        isFind = true ;
                        break;
                    }
                }
                if(isFind){
                    break;
                }
            }
            if(year==p.getYear() && month==p.getMonth()){
                return index ;
            }
        }
        return -1;
    }


    /**
     * 填充指标名称，将指标单位信息一并显示
     * @param name 指标名称
     * @param unit 指标单位
     * @return
     */
    public   String fullfillIndName(String name ,String unit){
        String regexCn = "（(.*?)）";  //中文括号
        String regexEn = "\\((.*?)\\)"; //英文括号
        //匹配中文括号
        Pattern p = Pattern.compile(regexCn);
        Matcher m = p.matcher(name);
        boolean isFind = false ;
        while (m.find()) {
            isFind = true ;
        }
        //匹配英文括号
        p = Pattern.compile(regexEn);
        m = p.matcher(name);
        while (m.find()) {
            isFind = true ;
        }
        if(!isFind&&(null!=unit&&!unit.equals(""))){
            return name+"（"+unit+"）";
        }
        return  name ;
    }
    /**
     * 读取行索引值
     *
     * @param regioncode
     * @param regions
     * @return
     */
    private int getRowIndex(String regioncode, Region[] regions) {
        for (int i=0,len=regions.length; i<len; i++) {
            if (regions[i].getRegionCode() == regioncode ||
                    regions[i].getRegionCode().equals(regioncode)) {
                return i;
            }
        }
        return -1;
    }


    //获取指标及子指标所有codes
    public List getIndCodes(MacroReIndicator r) {
        List<String> indCodes = new ArrayList<>();
        String code = r.getIdenCode();
        if(code!=null && !code.equals("") && !indCodes.contains(code)){
            indCodes.add(code);
        }
        List<MacroReIndicator> subs = r.getSubs();//子指标项（包括本级）
        for(MacroReIndicator sub:subs){
            indCodes.addAll(getIndCodes(sub));//嵌套子表头（支持多层表头）
        }
        return  indCodes;
    }

    /**
     * 多维表头（子指标项分组）扁平化封装
     *
     * @param p
     * @param r
     * @return
     */
    private List getIndCode(Period p ,MacroReIndicator r,Map<String,String> groupCodes){
        List<String> head = new ArrayList<>();
        List<Period> hasPeriods = r.getPeriods();//原数据指标对应报告期
        int count =0 ;
        for(Period period:hasPeriods){
            count =0 ;
            if(p.getReportType() == period.getReportType() ){
                count++;
            }
            if(p.getYear() == period.getYear() ){
                count++;
            }
            if(p.getMonth() == period.getMonth()){
                count++;
            }
            if(count ==3){
                break;
            }
        }
        //如果该时段下有此指标
        if(count == 3){
            if(!groupCodes.isEmpty()){
                if(groupCodes.get("'" + r.getIdenCode() + "'") != null){
                    head.add(r.getIdenCode());//本层指标编码
                }
            }else {
                head.add(r.getIdenCode());//本层指标编码
            }
            //存在【子指标】项
            List<MacroReIndicator> subs = r.getSubs();
            for(MacroReIndicator sub:subs){
                head.addAll(getIndCode(p,sub,groupCodes));//添加【子指标】项
            }
        }
        return  head ;
    }


    /**
     * 查找所有无子节点指标
     * @return
     */
    public List<TMacroTablemeta> findALLTablemetas(){
        List<TMacroTablemeta> allTableMetas = this.macroTablemetaDao.findAllTableMetas();
        return allTableMetas;
    }

    /**
     *
     */
    public int test(){
        BaseDaoImpl<TMacroTablemeta,Integer> new_dao = new BaseDaoImpl<>(TMacroTablemeta.class,entityManager);

        String hql = "from TMacroTablemeta";
        return new_dao.findCountByHql(hql);
    }
}
